package org.example4;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class JavaProxy {

    public static final String newLine ="\r\n";
    public static final String genProxyClazzName ="$Proxy0";

    public static Object newProxyInstance(JavaClassLoader classLoader,
                                          Class<?>[] interfaces,
                                          JavaInvocationHandler h){
        try {
            //1.动态生成源代码.java文件
            String src=generateSrc(interfaces);
            //2.java文件输出到磁盘
            String filePath=JavaProxy.class.getResource("").getPath();
            File file=new File(filePath +"/"+ genProxyClazzName+".java");
            FileWriter fw=new FileWriter(file);
            fw.write(src);
            fw.flush();
            fw.close();
            //3.把生成的.java文件编译成.class文件
            JavaCompiler compiler= ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manage=compiler.getStandardFileManager(null,null,null);
            Iterable iterable=manage.getJavaFileObjects(file);
            JavaCompiler.CompilationTask task=compiler.getTask(null,null,null,null,null,iterable);
            task.call();
            manage.close();

            //4.编译生成的.class文件加载到JVM中来
            Class proxyClass=classLoader.findClass(genProxyClazzName);
            Constructor c=proxyClass.getConstructor(JavaInvocationHandler.class);
//            file.delete();
            //5.返回字节码重组后新的对象
            return c.newInstance(h);
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    public static String generateSrc(Class<?>[] interfaces){
        StringBuffer sb=new StringBuffer();
        sb.append(JavaProxy.class.getPackage()+";" + newLine);
        sb.append("import java.lang.reflect.Method;"+ newLine);
        sb.append("public class "+genProxyClazzName+" implements " + interfaces[0].getName() + "{" + newLine);
        sb.append("public JavaInvocationHandler h;" + newLine);
        sb.append("public "+genProxyClazzName+"(JavaInvocationHandler h) { "+ newLine);
        sb.append("this.h=h;"+ newLine);
        sb.append("}"+ newLine);

        for (Method m:interfaces[0].getMethods()){
            sb.append("public "+ m.getReturnType().getName() + " " +m.getName() + "(){"+ newLine);
            sb.append("try{"+ newLine);
            sb.append("Method m="+interfaces[0].getName()+".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + newLine);
            sb.append("this.h.invoke(this,m,null);"+ newLine);
            sb.append("}catch(Throwable e){" + newLine);
            sb.append("e.printStackTrace();" + newLine);
            sb.append("}" + newLine);
            sb.append("}" + newLine);
        }
        sb.append("}" + newLine);
        return sb.toString();
    }
}